package my.suveng.sharding.algorithm;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import javax.annotation.PostConstruct;

import cn.hutool.core.collection.CollUtil;
import com.google.common.hash.Hashing;
import lombok.extern.slf4j.Slf4j;
import my.suveng.sharding.config.DataSourceConfigProperties;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author suwenguang
 * @date 2020/11/3 11:22 下午
 * @since 1.0
 */
@Component
@Slf4j
public class DataSourceRouteV1 extends AbstractDataSourceRoute {

	public static final int INITIAL_CAPACITY = 1024;
	@Autowired
	DataSourceConfigProperties dataSourceConfigProperties;

	public static final String VERSION = "001";

	private final ArrayList<String> weightList = new ArrayList<>(INITIAL_CAPACITY);

	/**
	 * 构造一致性hash数组, 权重, 需要保证每次构造的数组都是固定的
	 */
	@PostConstruct
	void init() {
		Map<String, Integer> weight = dataSourceConfigProperties.getWeight();
		List<String> dsNames = CollUtil.newArrayList(weight.keySet());
		if (CollUtil.isEmpty(dsNames)) {
			log.info("数据源实例权重配置为空");
			return;
		}

		AtomicInteger totalWeight = new AtomicInteger();
		weight.forEach((k, v) -> totalWeight.addAndGet(v));

		int dsCount = weight.size();
		Map<String, Integer> nodeSize = new HashMap<>(dsCount);
		for (String dsName : dsNames) {
			int size = INITIAL_CAPACITY / totalWeight.get() * weight.get(dsName);
			nodeSize.put(dsName, size);
		}

		// 顺序填入
		nodeSize.forEach((k, v) -> {
			for (int i = 0; i < v; i++) {
				weightList.add(k);
			}
		});
	}

	@Override
	public String route(Object id) {
		// 一致性hash算法, 相同的id取到的ds name是固定的
		int consistentHash = Hashing.consistentHash(id.hashCode(), INITIAL_CAPACITY);
		// 获取对应的 ds name
		return weightList.get(consistentHash);
	}
}
